﻿using AdvancedCollections;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Linq;

namespace AdvancedCollectionsTests
{
    [TestClass]
    public class AVLTreeTest
    {
        [TestMethod]
        public void TestAdd1()
        {
            var bt = new AVLTree<int>();

            Assert.AreEqual(true, bt.Add(5));
        }

        [TestMethod]
        public void TestAdd2()
        {
            var bt = new AVLTree<int>();

            Assert.AreEqual(true, bt.Add(5));
            Assert.AreEqual(false, bt.Add(5));
        }

        [TestMethod]
        public void TestAdd3()
        {
            var bt = new AVLTree<int>();
            int[] itemsToInsert = { 5, 7, 2, 1, 3, 9, 6, 8, 4 };

            foreach (var item in itemsToInsert)
            {
                Assert.AreEqual(true, bt.Add(item));
            }

            foreach (var item in itemsToInsert)
            {
                Assert.AreEqual(false, bt.Add(item));
            }
        }

        [TestMethod]
        public void TestAdd4()
        {
            var bt = new AVLTree<int>();

            foreach (var item in Enumerable.Range(1, 1000))
            {
                Assert.AreEqual(true, bt.Add(item));
            }

            foreach (var item in Enumerable.Range(1, 1000).Reverse())
            {
                Assert.AreEqual(false, bt.Add(item));
            }
        }

        [TestMethod]
        public void TestContains1()
        {
            var bt = new AVLTree<int>();

            Assert.AreEqual(false, bt.Contains(5));
        }

        [TestMethod]
        public void TestContains2()
        {
            var bt = new AVLTree<int>();

            Assert.AreEqual(false, bt.Contains(5));
            bt.Add(5);
            Assert.AreEqual(true, bt.Contains(5));
        }

        [TestMethod]
        public void TestContains3()
        {
            var bt = new AVLTree<int>();
            int[] itemsToInsert = { 5, 7, 2, 1, 3, 9, 6, 8, 4 };

            foreach (var item in itemsToInsert)
            {
                Assert.AreEqual(false, bt.Contains(item));
                bt.Add(item);
            }

            foreach (var item in itemsToInsert)
            {
                Assert.AreEqual(true, bt.Contains(item));
            }
        }

        [TestMethod]
        public void TestContains4()
        {
            var bt = new AVLTree<int>();

            foreach (var item in Enumerable.Range(1, 1000))
            {
                Assert.AreEqual(false, bt.Contains(item));
                bt.Add(item);
            }

            foreach (var item in Enumerable.Range(1, 1000).Reverse())
            {
                Assert.AreEqual(true, bt.Contains(item));
            }
        }

        [TestMethod]
        public void TestCount1()
        {
            var bt = new AVLTree<int>();

            Assert.AreEqual(0, bt.Count);
        }

        [TestMethod]
        public void TestCount2()
        {
            var bt = new AVLTree<int>();

            Assert.AreEqual(0, bt.Count);
            bt.Add(5);
            Assert.AreEqual(1, bt.Count);
            bt.Remove(4);
            Assert.AreEqual(1, bt.Count);
            bt.Remove(5);
            Assert.AreEqual(0, bt.Count);
        }

        [TestMethod]
        public void TestCount3()
        {
            var bt = new AVLTree<int>();
            int[] itemsToInsert = { 5, 7, 2, 1, 3, 9, 6, 8, 4 };
            int myCount = 0;

            foreach (var item in itemsToInsert)
            {
                Assert.AreEqual(myCount, bt.Count);
                bt.Add(item);
                myCount++;
                Assert.AreEqual(myCount, bt.Count);
            }

            foreach (var item in itemsToInsert)
            {
                Assert.AreEqual(myCount, bt.Count);
                bt.Remove(item);
                myCount--;
                Assert.AreEqual(myCount, bt.Count);
            }
        }

        [TestMethod]
        public void TestCount4()
        {
            var bt = new AVLTree<int>();
            int myCount = 0;

            foreach (var item in Enumerable.Range(1, 1000))
            {
                Assert.AreEqual(myCount, bt.Count);
                bt.Add(item);
                myCount++;
                Assert.AreEqual(myCount, bt.Count);
            }

            foreach (var item in Enumerable.Range(1, 1000).Reverse())
            {
                Assert.AreEqual(myCount, bt.Count);
                bt.Remove(item);
                myCount--;
                Assert.AreEqual(myCount, bt.Count);
            }
        }

        [TestMethod]
        public void TestEnumerator1()
        {
            var bt = new AVLTree<int>();
            int[] itemsToInsert = { 5, 7, 2, 1, 3, 9, 6, 8, 4 };
            int[] itemsToRead = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
            int i = 0;

            foreach (var item in itemsToInsert)
            {
                bt.Add(item);
            }

            foreach (var item in bt)
            {
                Assert.AreEqual(itemsToRead[i], item);
                i++;
            }
        }

        [TestMethod]
        public void TestEnumerator2()
        {
            var bt = new AVLTree<int>();

            int from = 1, count = 1000;
            List<int> itemsToRead = new List<int>(Enumerable.Range(from, count));
            int i = 0;

            foreach (var item in Enumerable.Range(from, count).Reverse())
            {
                bt.Add(item);
            }

            foreach (var item in bt)
            {
                Assert.AreEqual(itemsToRead[i], item);
                i++;
            }
        }

        [TestMethod]
        public void TestRemove1()
        {
            var bt = new AVLTree<int>();

            Assert.AreEqual(false, bt.Remove(5));
        }

        [TestMethod]
        public void TestRemove2()
        {
            var bt = new AVLTree<int>();

            bt.Add(5);
            Assert.AreEqual(true, bt.Remove(5));
            Assert.AreEqual(false, bt.Contains(5));
            Assert.AreEqual(false, bt.Remove(5));
        }

        [TestMethod]
        public void TestRemove3()
        {
            var bt = new AVLTree<int>();
            int[] itemsToInsert = { 5, 7, 2, 1, 3, 9, 6, 8, 4 };

            foreach (var item in itemsToInsert)
            {
                bt.Add(item);
            }

            foreach (var item in itemsToInsert)
            {
                Assert.AreEqual(true, bt.Contains(item));
                Assert.AreEqual(true, bt.Remove(item));
                Assert.AreEqual(false, bt.Contains(item));
                Assert.AreEqual(false, bt.Remove(item));
            }
        }

        [TestMethod]
        public void TestRemove4()
        {
            var bt = new AVLTree<int>();

            foreach (var item in Enumerable.Range(1, 1000))
            {
                bt.Add(item);
            }

            foreach (var item in Enumerable.Range(1, 1000).Reverse())
            {
                Assert.AreEqual(true, bt.Contains(item));
                Assert.AreEqual(true, bt.Remove(item));
                Assert.AreEqual(false, bt.Contains(item));
                Assert.AreEqual(false, bt.Remove(item));
            }
        }
    }
}